package private

import (
	"context"
	"fmt"
	"gitee.com/wanjimao/dongli-kit/pkg"
	errors2 "gitee.com/wanjimao/dongli-platform/services/profile/errors"
	"gitee.com/wanjimao/dongli-platform/tools"
	"gitee.com/wanjimao/dongli-util/dancetiktok"
	"gitee.com/wanjimao/dongli-util/dancetiktok/model/dancetiktokmodelmysql"
	"gitee.com/wanjimao/dongli-util/helper"
	"gorm.io/gorm"
	"strconv"
	"time"

	"gitee.com/wanjimao/dongli-kit/mq/miface"
	"go.uber.org/zap"

	pb "gitee.com/wanjimao/dongli-platform/api/gen/knapsack/api"
	"gitee.com/wanjimao/dongli-platform/services/knapsack/changes"
	"gitee.com/wanjimao/dongli-platform/services/knapsack/errors"
)

func (s *Service) AddItem(_ context.Context, request *pb.AddItemPrivateRequest) (*pb.AddItemPrivateResponse, error) {
	if dao, err := s.db.LoadOrCreateKnapsack(request.Uid); err != nil {
		s.logger.Error("load knapsack failed", zap.Error(err))
		return nil, errors.ErrNotFound
	} else if err := dao.Update(func() bool {
		if len(request.GetFeatures()) > 0 {
			dao.AddFeatures(request.GetFeatures())
		}
		if len(request.GetItems()) > 0 {
			dao.AddItems(request.GetItems())
		}
		return true
	}); err != nil {
		s.logger.Error("add item failed", zap.Error(err))
		return nil, errors.ErrGeneralFailure
	} else if err := s.pubChanges(request.Uid, dao.GetAndDeleteChanges(request.Items, nil, request.Source)); err != nil {
		s.logger.Error("publish knapsack changes failed", zap.Error(err))
		return nil, errors.ErrGeneralFailure
	}
	return &pb.AddItemPrivateResponse{}, nil
}

func (s *Service) pubChanges(uid string, modify *pb.KnapsackModify) error {
	if modify.Knapsack == nil {
		return nil
	}
	topic := changes.CreateTopic(uid)
	if data, err := changes.Pack(modify); err != nil {
		s.logger.Error("marshal knapsack failed", zap.Error(err))
		return err
	} else if err := s.mq.Publish(topic, miface.WithBytes(data)); err != nil {
		s.logger.Error("publish knapsack changes failed", zap.Error(err))
		return err
	}
	return nil
}

func (s *Service) RemoveItem(_ context.Context, request *pb.RemoveItemPrivateRequest) (*pb.RemoveItemPrivateResponse, error) {
	if dao, err := s.db.LoadKnapsack(request.Uid); err != nil {
		s.logger.Error("load knapsack failed", zap.Error(err))
		return nil, errors.ErrNotFound
	} else if err := dao.Update(func() bool {
		if err := dao.RemoveItems(request.GetItems()); err != nil {
			s.logger.Error("remove item failed", zap.Error(err))
			return false
		}
		return true
	}); err != nil {
		return nil, errors.ErrNotEnough
	} else if err := s.pubChanges(request.Uid, dao.GetAndDeleteChanges(nil, request.Items, request.Source)); err != nil {
		s.logger.Error("publish knapsack changes failed", zap.Error(err))
		return nil, errors.ErrGeneralFailure
	}
	return &pb.RemoveItemPrivateResponse{}, nil
}

func (s *Service) GetItemById(_ context.Context, request *pb.GetItemByIdPrivateRequest) (*pb.GetItemByIdPrivateResponse, error) {
	if dao, err := s.db.LoadKnapsack(request.Uid); err != nil {
		s.logger.Error("load knapsack failed", zap.Error(err))
		return nil, errors.ErrNotFound
	} else {
		item := dao.Data.Items[request.ItemId]
		return &pb.GetItemByIdPrivateResponse{Item: item}, nil
	}

}

func (s *Service) GetKnapsack(_ context.Context, request *pb.GetKnapsackRequest) (*pb.GetKnapsackResponse, error) {
	if dao, err := s.db.LoadKnapsack(request.Uid); err != nil {
		s.logger.Error("load knapsack failed", zap.Error(err))
		return nil, errors.ErrNotFound
	} else {
		return &pb.GetKnapsackResponse{Knapsack: dao.Data}, nil
	}

}

func (s *Service) GrantCreateRoleElement(_ context.Context, request *pb.GrantCreateRoleElementRequest) (*pb.GrantCreateRoleElementResponse, error) {
	logInfo := pkg.LogInfo{
		Method:     "GrantCreateRoleElement",
		TimeString: time.Now().Format(time.DateTime),
		TimeUnix:   time.Now().Unix(),
		UserId:     0,
		Req:        helper.InterfaceHelperObject.ToString(request),
		LogId:      request.LogId,
	}
	//查询用户角色数据
	resp := &pb.GrantCreateRoleElementResponse{}
	//用户
	var accountRole dancetiktokmodelmysql.DanceUserAccountRole
	tx := s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceUserAccountRole{}).Where("id = ?", request.RoleId).First(&accountRole)
	if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
		s.logger.Error(fmt.Sprintf("查询角色异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return resp, errors2.ErrLoadFailure
	}
	if accountRole.Id == 0 || accountRole.AccountId == 0 {
		s.logger.Error(fmt.Sprintf("取出的数据异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return resp, errors2.ErrNotFound
	}

	avatarFrame, _ := strconv.ParseInt(tools.GlobalDataMapInitInitialProps[1].Items, 10, 64)
	scoreBackgroundCard, _ := strconv.ParseInt(tools.GlobalDataMapInitInitialProps[2].Items, 10, 64)
	roomBackgroundCard, _ := strconv.ParseInt(tools.GlobalDataMapInitInitialProps[3].Items, 10, 64)
	dynamicBackgroundCard, _ := strconv.ParseInt(tools.GlobalDataMapInitInitialProps[4].Items, 10, 64)
	dJBooth, _ := strconv.ParseInt(tools.GlobalDataMapInitInitialProps[5].Items, 10, 64)
	base, _ := strconv.ParseInt(tools.GlobalDataMapInitInitialProps[6].Items, 10, 64)

	begin := s.mysqlDb.MysqlDanceDb.Begin()
	m := make(map[string]interface{})
	m["avatar_frame"] = avatarFrame
	m["score_background_card"] = scoreBackgroundCard
	m["room_background_card"] = roomBackgroundCard
	m["dynamic_background_card"] = dynamicBackgroundCard
	m["dj_booth"] = dJBooth
	m["base"] = base
	//删除后重新插入
	//todo 开启事务   UPDATE `dance_level` SET `level`=6,`max_limit`=500,`min_limit`=401,`update_id`=1,`updated_at`='2023-10-08 13:10:43.936' WHERE id = 5 AND `dance_level`.`deleted_at` IS NULL
	if update := begin.Model(&dancetiktokmodelmysql.DanceUserAccountRole{}).Where("id = ?", request.RoleId).Updates(&m); nil != update.Error {
		s.logger.Error(fmt.Sprintf("更新的数据异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		begin.Rollback()
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return resp, errors2.ErrNotFound
	}
	//todo 新增数据详情表
	needInsert := make([]dancetiktokmodelmysql.DanceBag, 0)
	for _, idTmp := range tools.GlobalDataMapInitInitialProps {
		id, _ := strconv.ParseInt(idTmp.Items, 10, 64)
		if id == 0 {
			continue
		}
		addElement := dancetiktokmodelmysql.DanceBag{
			No:         id,
			RoleId:     request.RoleId,
			Number:     1,
			ExpireTime: 0,
			CreateId:   request.RoleId,
			UpdateId:   request.RoleId,
			CreatedAt:  time.Now(),
			UpdatedAt:  time.Now(),
			DeletedAt:  gorm.DeletedAt{},
		}
		needInsert = append(needInsert, addElement)
	}
	if create := begin.Model(&dancetiktokmodelmysql.DanceBag{}).Create(&needInsert); nil != create.Error {
		s.logger.Error(fmt.Sprintf("插入数据异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		begin.Rollback()
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return resp, errors2.ErrNotFound
	}
	//todo INSERT INTO `dance_level_element` (`level`,`element_id`,`create_id`,`update_id`,`created_at`,`updated_at`,`deleted_at`) VALUES (3,2,1,1,'2023-08-30 10:55:58.393','2023-08-30 10:55:58.393',NULL)
	if resCommit := begin.Commit(); nil != resCommit.Error {
		begin.Rollback()
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return resp, errors2.ErrNotFound
	}
	return resp, nil
}

func (s *Service) ItemList(_ context.Context, request *pb.ItemListRequest) (*pb.ItemListResponse, error) {
	logInfo := pkg.LogInfo{
		Method:     "ItemList",
		TimeString: time.Now().Format(time.DateTime),
		TimeUnix:   time.Now().Unix(),
		UserId:     0,
		Req:        helper.InterfaceHelperObject.ToString(request),
		LogId:      request.LogId,
	}
	//查询用户角色数据
	resp := &pb.ItemListResponse{}
	//用户
	var bags []dancetiktokmodelmysql.DanceBag
	tx := s.mysqlDb.MysqlDanceDb.Model(&dancetiktokmodelmysql.DanceBag{}).Where("role_id = ?", request.RoleId).Find(&bags)
	if nil != tx.Error && gorm.ErrRecordNotFound != tx.Error {
		s.logger.Error(fmt.Sprintf("查询角色异常 logInfo:%+v err:%+v", logInfo, tx.Error))
		resp.ErrCode = dancetiktok.ErrorLoginDataException
		return resp, errors2.ErrLoadFailure
	}
	resp.TbItem = make([]*pb.SItem, 0)
	for _, bag := range bags {
		resp.TbItem = append(resp.TbItem, &pb.SItem{
			Id:        uint32(bag.No),
			InitTime:  uint32(bag.CreatedAt.Unix()),
			ValidTime: uint32(bag.ExpireTime),
			Num:       uint32(bag.Number),
		})
	}
	return resp, nil
}
